package com.printeverywhere.action;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.hibernate.HibernateException;
import org.hibernate.PropertyValueException;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.validator.CreditCardNumber;

import paypal.payflow.Invoice;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.validator.annotations.DoubleRangeFieldValidator;
import com.opensymphony.xwork2.validator.annotations.EmailValidator;
import com.paypal.sdk.exceptions.PayPalException;
import com.paypal.sdk.profiles.APIProfile;
import com.paypal.sdk.profiles.ProfileFactory;
import com.paypal.sdk.services.CallerServices;
import com.paypal.soap.api.DoDirectPaymentResponseType;
import com.printeverywhere.delegator.CommonFunctionDelegator;
import com.printeverywhere.delegator.CreditCardServiceDelegator;
import com.printeverywhere.delegator.CurrencyServiceDelegator;
import com.printeverywhere.delegator.DepositsServiceDelegator;
import com.printeverywhere.delegator.TransactionsServiceDelegator;
import com.printeverywhere.delegator.UserServiceDelegator;
import com.printeverywhere.dto.AdminDetails;
import com.printeverywhere.dto.AuctionInvoices;
import com.printeverywhere.dto.Creditcard;
import com.printeverywhere.dto.Currency;
import com.printeverywhere.dto.Deposits;
import com.printeverywhere.dto.GeneralOptions;
import com.printeverywhere.dto.Transactions;
import com.printeverywhere.dto.User;
import com.printeverywhere.dto.UsersInfo;
import com.printeverywhere.util.AdminConstants;
import com.printeverywhere.util.AttributeConstants;
import com.printeverywhere.util.DateUtil;
import com.printeverywhere.util.PayPalUtil;
import com.printeverywhere.util.SearchCriteria;
import com.printeverywhere.util.SearchListCriteria;
import com.printeverywhere.util.SessionUtil;

public class MoneyManagerAction extends FrontBaseSupport implements
		ServletRequestAware {

	public MoneyManagerAction() {
		super(true, false);
	}

	/**  */
	private static final long serialVersionUID = 1L;

	private List<Creditcard> creditCardList;

	private SearchCriteria searchCriteria = new SearchCriteria();

	private SearchListCriteria searchListCriteria = new SearchListCriteria();

	private HttpServletRequest request;

	private Deposits deposits;

	private Transactions transactions;

	private User user;

	private Creditcard creditcard;

	private User accountDetailList;

	private List<Deposits> depositsList = new ArrayList<Deposits>();

	private UsersInfo usersInfo;

	private List<Currency> currencyList = new ArrayList<Currency>();

	private List<Transactions> transactionList = new ArrayList<Transactions>();

	private List<AuctionInvoices> invoicesList = new ArrayList<AuctionInvoices>();

	private AuctionInvoices auctionInvoices = new AuctionInvoices();

	private AdminDetails adminDetails = new AdminDetails();

	private double amount;

	private String nameOnCard = AdminConstants.NONE;

	private static Logger logger = Logger.getLogger(MoneyManagerAction.class);

	private String paypalEmail = AdminConstants.NONE;

	private String currency = AdminConstants.NONE;

	private GeneralOptions generalOptions;

	private Date fromDate;

	private Date toDate;

	@Override
	public String execute() throws Exception {
		try{
			getList();
		}catch (ConstraintViolationException e) {
			logger.info("Constraint violated...." + e.getConstraintName() + " : " + e.getMessage());
		}catch (PropertyValueException e) {
			logger.info("Property Value Exception.... : " + e.getMessage());
		}catch (HibernateException e) {
			logger.info("Hibernate Exception.... : " + e.getMessage());
		}
		return SUCCESS;
	}

	public String updateCreditCardDeposit() {
		try {
			Date date = DateUtil.getTodaysDate();
			user = SessionUtil.getUser(request);
			generalOptions = (GeneralOptions) ActionContext.getContext().getApplication().get(AdminConstants.GENERAL_OPTIONS);
			deposits = DepositsServiceDelegator.get(user.getLastPaidDate());
			if(amount < generalOptions.getMinimumPayment()){
				getList();
				addActionError("Minimum payment amount can not be less than "+ generalOptions.getMinimumPayment());
				return INPUT;
			}

			user.setCurrentBalance(user.getCurrentBalance() + (amount));
			user.setTotalPaid(amount);
			user.setLastPaidDate(date);
			UserServiceDelegator.updateUser(user);

			Deposits newDeposits = new Deposits();
			newDeposits.setAmount(amount);
			newDeposits.setDepositDate(date);
			newDeposits.setUser(user);
			newDeposits.setSource(nameOnCard);
			DepositsServiceDelegator.add(newDeposits);
			transactions = new Transactions();
			transactions.setAmount(amount);
			transactions.setBalance(amount + user.getCurrentBalance());
			transactions.setDate(date);
			if(user.getCurrentBalance() < amount){
				transactions.setDue(amount - user.getCurrentBalance());
			}else{
				transactions.setDue(0.0);
			}
			transactions.setInvoice(null);
			transactions.setTitle(AdminConstants.BLANK);
			TransactionsServiceDelegator.add(transactions);
		} catch (HibernateException e) {
			getList();
			logger.info("--------------->");
			return INPUT;
		}
		return SUCCESS;
	}

	public String makePaypalDeposit(){
		try {
			CallerServices caller = new CallerServices();
			APIProfile profile = ProfileFactory.createSSLAPIProfile();
			profile.setAPIUsername("sdk-seller_api1.sdk.com");
			profile.setAPIPassword("12345678");
			profile.setCertificateFile(ServletActionContext.getServletContext().getRealPath("Cert/sdk-seller.p12"));
			profile.setPrivateKeyPassword("password");
			profile.setEnvironment("beta-sandbox");
			caller.setAPIProfile(profile);
			user = SessionUtil.getUser(request);

			creditcard = user.getCreditcard();

			DoDirectPaymentResponseType response =  PayPalUtil.DoDirectPayment(caller, creditcard, amount, currency);
			double balance = 0.0;

			deposits = new Deposits();
			if(user.getCurrentBalance() < 0){
				balance = user.getCurrentBalance() + amount;
			}
			if(balance < 0){
				transactions.setDue(balance);
			}else{
				transactions.setDue(0.0);
			}
			if(response.getTransactionID() != null){
				deposits.setAmount(amount);
				deposits.setSource(response.getTransactionID());
				deposits.setDepositDate(DateUtil.getTodaysDate());
				deposits.setUser(user);
				DepositsServiceDelegator.add(deposits);
			}else{
				addActionError("Payment Error: Credit card processing error. \n Please go back and check your credit card information. \n The merchant login ID or password is invalid or the account is inactive. ");
				getList();
				currencyList = CurrencyServiceDelegator.getList();
				return INPUT;
			}
			addActionMessage(" Paypal transaction completed successfully. ");
		} catch (PayPalException e) {
			getList();
			addActionError("Payment Error: Credit card processing error. \n Please go back and check your credit card information. \n The merchant login ID or password is invalid or the account is inactive. ");
			return INPUT;
		}catch (Exception e) {
			getList();
			addActionError("Payment Error: Credit card processing error. \n Please go back and check your credit card information. \n The merchant login ID or password is invalid or the account is inactive. ");
			return INPUT;
		}
		return SUCCESS;
	}

	public String transactionNotYetInvoiced(){
		try {
			user = SessionUtil.getUser(request);
			searchListCriteria.removeAllAttribute();
			searchListCriteria.setAttribute(AdminConstants.USER, new Object[]{user, SearchListCriteria.EQ});
			searchListCriteria.setAttribute("invoice.invoice", new Object[]{null, SearchListCriteria.ISNULL});
			transactionList = TransactionsServiceDelegator.getList(searchListCriteria);
		} catch (Exception e) {
			return INPUT;
		}
		return SUCCESS;
	}

	public String invoices(){
		try {
			List<Criterion> criterionList = new ArrayList<Criterion>();
			if((request.getParameter("fromDate") != null && !request.getParameter("fromDate").equals(AdminConstants.NONE)) && (request.getParameter("toDate") != null && !request.getParameter("toDate").equals(AdminConstants.NONE))){
				fromDate = DateUtil.getDate(request.getParameter("fromDate"), "yyyy-MM-dd");
				toDate = DateUtil.getDate(request.getParameter("toDate"), "yyyy-MM-dd");
				criterionList.add(Restrictions.ge("start", fromDate));
				criterionList.add(Restrictions.le("ends", toDate));
			}
			user = SessionUtil.getUser(request);
			fromDate = DateUtil.getTodaysDate();
			toDate = DateUtil.getTodaysDate();
			criterionList.add(Restrictions.eq(AdminConstants.USER, user));
			invoicesList = (List<AuctionInvoices>) CommonFunctionDelegator.getObjectsByCriterion(criterionList, null, null, AuctionInvoices.class);
		} catch (Exception e) {
			return INPUT;
		}
		return SUCCESS;
	}

	public String viewInvoiceDetails(){
		try {
			if(request.getParameter("invoice") != null && !request.getParameter("invoice").equals(AdminConstants.NONE)){
				SearchCriteria searchCriteria = new SearchCriteria();
				searchCriteria.setAttribute("invoice", request.getParameter("invoice"));
				List<AuctionInvoices> auctionInvoicesList = (List<AuctionInvoices>) CommonFunctionDelegator.getObjectBySearchCriteria(searchCriteria, AuctionInvoices.class);

				this.auctionInvoices = (auctionInvoicesList != null && auctionInvoicesList.size() > 0) ? auctionInvoicesList.get(0) : null;
				user = SessionUtil.getUser(request);
				List<Criterion> criterionList = new ArrayList<Criterion>();
				criterionList.add(Restrictions.eq("invoice", this.auctionInvoices));
				this.transactionList = (List<Transactions>) CommonFunctionDelegator.getObjectsByCriterion(criterionList, null, null, Transactions.class);
				this.adminDetails = (AdminDetails) CommonFunctionDelegator.getAllfromtable(AdminDetails.class.getName()).get(0);
			}
		} catch (Exception e) {
			return INPUT;
		}
		return SUCCESS;
	}

	public String viewAccountSheet(){
		try{
			User user = SessionUtil.getUser(request);
			int accountDetailid = user.getId();
			fromDate = DateUtil.getTodaysDate();
			toDate = DateUtil.getTodaysDate();
			accountDetailList = UserServiceDelegator.getUser(accountDetailid);
			this.usersInfo = (UsersInfo) CommonFunctionDelegator.getObjectById("user.id", accountDetailList.getId(), UsersInfo.class);
			SearchCriteria searchCriteria = new SearchCriteria();
			searchCriteria.setAttribute("user", accountDetailList);
			depositsList = (List<Deposits>) CommonFunctionDelegator.getObjectBySearchCriteria(searchCriteria, Deposits.class);
		}catch (Exception e) {
			return INPUT;
		}
		return SUCCESS;
	}

	public String searchAccountSheets(){
		try {
			if(request.getParameter("userId") != null) {
				SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
				Date fromDate = simpleDateFormat.parse(request.getParameter("fromDate").substring(0, 10));
				Date toDate = simpleDateFormat.parse(request.getParameter("toDate").substring(0, 10));

				accountDetailList = UserServiceDelegator.getUser(Integer.parseInt(request.getParameter("userId")));
				List<Criterion> criterionList = new ArrayList<Criterion>();
				criterionList.add(Restrictions.ge("depositDate", fromDate));
				criterionList.add(Restrictions.le("depositDate", toDate));
				depositsList = (List<Deposits>) CommonFunctionDelegator.getObjectsByCriterion(criterionList, null, null, Deposits.class);
			}
		} catch (Exception e) {
			// TODO: handle exception
		}
		return SUCCESS;
	}
	public String deleteInvoice(){
		try {
			if(request.getParameter("invoice") != null && !request.getParameter("invoice").equals(AdminConstants.NONE)){
				String invoice = request.getParameter("invoice");
				searchCriteria.removeAllAttribute();
				searchCriteria.setAttribute("invoice", invoice);
				List<AuctionInvoices> invoiceList = (List<AuctionInvoices>) CommonFunctionDelegator.getObjectBySearchCriteria(searchCriteria, AuctionInvoices.class);
				if(invoiceList != null && invoiceList.size() > 0){
					AuctionInvoices auctionInvoices = invoiceList.get(0);
					CommonFunctionDelegator.GeneralDelete(auctionInvoices);
					addActionMessage("Invoice successfully deleted.");
				}
			}
		} catch (Exception e) {
			addActionMessage("Invoice not deleted.");
			return INPUT;
		}
		return SUCCESS;
	}


	public void getList(){
		user = SessionUtil.getUser(request);
		generalOptions = (GeneralOptions) ActionContext.getContext().getApplication().get(AdminConstants.GENERAL_OPTIONS);
		searchCriteria.removeAllAttribute();
		searchCriteria.setAttribute(AttributeConstants.USER, SessionUtil
				.getUser(request));
		creditCardList = CreditCardServiceDelegator.getList(searchCriteria);
		currencyList = CurrencyServiceDelegator.getList();
	}
	public void setServletRequest(HttpServletRequest arg0) {
		request = arg0;
	}

	public List<Creditcard> getCreditCardList() {
		return creditCardList;
	}

	public void setCreditCardList(List<Creditcard> creditCardList) {
		this.creditCardList = creditCardList;
	}

	public Deposits getDeposits() {
		return deposits;
	}

	public void setDeposits(Deposits deposits) {
		this.deposits = deposits;
	}

	public Transactions getTransactions() {
		return transactions;
	}

	public void setTransactions(Transactions transactions) {
		this.transactions = transactions;
	}

	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	@DoubleRangeFieldValidator(minInclusive="0.0", message="Enter positive value")
	public double getAmount() {
		getList();
		return amount;
	}

	public void setAmount(double amount) {
		this.amount = amount;
	}

	public String getNameOnCard() {
		return nameOnCard;
	}

	public void setNameOnCard(String nameOnCard) {
		this.nameOnCard = nameOnCard;
	}

	public Creditcard getCreditcard() {
		return creditcard;
	}

	public void setCreditcard(Creditcard creditcard) {
		this.creditcard = creditcard;
	}

	public List<Currency> getCurrencyList() {
		return currencyList;
	}

	public void setCurrencyList(List<Currency> currencyList) {
		this.currencyList = currencyList;
	}

	@EmailValidator(message="Enter valid email address.")
	public String getPaypalEmail() {
		getList();
		return paypalEmail;
	}

	public void setPaypalEmail(String paypalEmail) {
		this.paypalEmail = paypalEmail;
	}

	public String getCurrency() {
		return currency;
	}

	public void setCurrency(String currency) {
		this.currency = currency;
	}

	public GeneralOptions getGeneralOptions() {
		return generalOptions;
	}

	public void setGeneralOptions(GeneralOptions generalOptions) {
		this.generalOptions = generalOptions;
	}

	public List<Transactions> getTransactionList() {
		return transactionList;
	}

	public void setTransactionList(List<Transactions> transactionList) {
		this.transactionList = transactionList;
	}

	public List<AuctionInvoices> getInvoicesList() {
		return invoicesList;
	}

	public void setInvoicesList(List<AuctionInvoices> invoicesList) {
		this.invoicesList = invoicesList;
	}

	public Date getFromDate() {
		return fromDate;
	}

	public void setFromDate(Date fromDate) {
		this.fromDate = fromDate;
	}

	public Date getToDate() {
		return toDate;
	}

	public void setToDate(Date toDate) {
		this.toDate = toDate;
	}

	public AuctionInvoices getAuctionInvoices() {
		return auctionInvoices;
	}

	public void setAuctionInvoices(AuctionInvoices auctionInvoices) {
		this.auctionInvoices = auctionInvoices;
	}

	public AdminDetails getAdminDetails() {
		return adminDetails;
	}

	public void setAdminDetails(AdminDetails adminDetails) {
		this.adminDetails = adminDetails;
	}

	public User getAccountDetailList() {
		return accountDetailList;
	}

	public void setAccountDetailList(User accountDetailList) {
		this.accountDetailList = accountDetailList;
	}

	public UsersInfo getUsersInfo() {
		return usersInfo;
	}

	public void setUsersInfo(UsersInfo usersInfo) {
		this.usersInfo = usersInfo;
	}

	public List<Deposits> getDepositsList() {
		return depositsList;
	}

	public void setDepositsList(List<Deposits> depositsList) {
		this.depositsList = depositsList;
	}

}